package com.danco.training.zaneuskaya.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.danco.training.zaneuskaya.api.OrderService;
import com.danco.training.zaneuskaya.connection.HibernateSessionUtil;
import com.danco.training.zaneuskaya.connection.dao.OrderDao;
import com.danco.training.zaneuskaya.connection.dao.impl.OrderDaoImpl;
import com.danco.training.zaneuskaya.cswworker.CSVReader;
import com.danco.training.zaneuskaya.cswworker.CSVSaver;
import com.danco.training.zaneuskaya.cswworker.Separator;
import com.danco.training.zaneuskaya.domain.Book;
import com.danco.training.zaneuskaya.domain.Order;


public class OrderServiceImpl implements OrderService {

	private BookServiceImpl bookServiceImpl = BookServiceImpl
			.getBookStorageSeviceImplInstance();
	private static final Logger logger = Logger
			.getLogger(OrderServiceImpl.class);

	private static OrderServiceImpl orderStorageServiceInstance;

	private OrderDao orderDao = new OrderDaoImpl();

	

	public OrderServiceImpl() {

	}

	public List<Order> getList() {
		Transaction transaction = null;
		List<Order> res = new ArrayList<Order>();
		Session session = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			res.addAll(orderDao.readAll(session));

			transaction.commit();

		} catch (HibernateException e) {
			transaction.rollback();
			logger.error(e.getMessage(), e);

		}

		return res;
	}

	public List<Order> getExecutedOrders() {
		List<Order> res = null;
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			res = orderDao.readExecutedOrders(session);
			transaction.commit();
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}
		logger.trace("Excecuted orders  are founded");
		return res;
	}

	public List<Order> getNotExecutedOrders() {
		List<Order> res = null;
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			res = orderDao.readNotExecutedOrders(session);
			transaction.commit();
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

		logger.trace("Not excecuted orders  are founded");
		return res;
	}

	public List<Order> getExecutedOrdersForPeriod(Date from, Date to) {
		List<Order> res = null;
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			res = orderDao.readExecutedOrdersForPeriod(session, from, to);
			transaction.commit();
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

		logger.trace("Excecuted orders for period are founded");
		return res;
	}

	public List<Order> getOrdersSortedByOrderDate() {
		List<Order> res = null;
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			res = orderDao.readOrdersSortedByOrderDate(session);
			transaction.commit();
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

		logger.trace("Orders are sorted by execution date");
		return res;
	}

	public List<Order> getOrdersSortedByTotalPrice() {
		List<Order> res = null;
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			res = orderDao.readOrdersSortedByTotalPrice(session);
			transaction.commit();
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

		logger.trace("Orders are sorted by total price");
		return res;
	}

	public List<Order> getOrdersSortedByOrderState() {
		List<Order> orders = null;
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			orders = orderDao.readOrdersSortedByOrderState(session);
			transaction.commit();
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

		logger.trace("Orders are sorted by state");
		return orders;

	}

	public List<Order> getExecutedOrdersSortedByOrderDate(Date from, Date to) {
		List<Order> res = new ArrayList<Order>();
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			res = orderDao.readExecutedOrdersSortedByOrderDate(session, from,
					to);
			transaction.commit();
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

		logger.trace("Executed orders are sorted by execution date");

		return res;
	}

	public List<Order> getExecutedOrdersSortedByPrice(Date from, Date to) {
		List<Order> res = new ArrayList<Order>();
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction= session.beginTransaction();
			res = orderDao.readExecutedOrdersSortedByPrice(session, from, to);
			transaction.commit();
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

		logger.trace("Executed orders are sorted by price");
		return res;
	}

	public Order getById(Integer id) {
		Order order = null;
		Transaction transaction = null;
		Session session = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			order = orderDao.read(session, id);
			List<Book> books = orderDao.findBooksByOrderId(session,
					order.getId());
			order.setBooks(books);
			
			transaction.commit();

		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();

		}

		logger.info("Order not founded in Orderstorage ");
		return order;
	}

	public boolean addBookToOrder(Order order, Book book) {
		Transaction transaction = null;
		Session session = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			orderDao.addBookOrder(session, order, book);
			transaction.commit();
			return true;
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

		return false;
	}

	public boolean removeBookFromOrder(Order order, Book book) {
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			
			orderDao.removeBookOrder(session, order, book);
			transaction.commit();
			return true;
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();

		}

		return false;
	}

	public double countPrice(Order order) {

		double sum = 0;
		for (Book book : order.getBooks()) {
			sum += book.getPrice() * book.getQuantity();
		}
		return sum;
	}

	public Order createOrderCopy(Order order) throws CloneNotSupportedException {
		Order copy = order.clone();
		copy.setBooks(order.getBooks());
		copy.setExecuted(order.isExecuted());
		copy.setTotalPrice(order.getTotalPrice());
		copy.setOrderDate(order.getOrderDate());
		Session session = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			orderDao.create(session, copy);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);

		}
		return copy;
	}

	public void saveEntityListToFile(String file) {
		ArrayList<String> res = new ArrayList<String>();
		for (Order b : getList()) {
			res.add(entityDetails(b));
		}
		try {
			CSVSaver.saveListToFile(file, res);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
	}

	public ArrayList<Order> readEntityList(String file) {
		ArrayList<Order> res = new ArrayList<Order>();
		for (int i = 0; i < CSVReader.readList(file).size(); i++) {
			String order[] = CSVReader.readFile(file)[i]
					.split(Separator.SEPARATOR.getS());
			Order or = new Order(Integer.parseInt(order[0]));
			addEntity(or);
			String books[] = order[1].split(Separator.BOOK_SEPARATOR_IN_ORDER
					.getS());
			for (int j = 0; j < books.length - 1; j++) {
				addBookToOrder(or,
						bookServiceImpl.getById(Integer.parseInt(books[j])));
			}
			or.setExecuted(Boolean.parseBoolean(order[2]));
			or.setTotalPrice(Double.parseDouble(order[3]));
			res.add(or);
		}
		return res;
	}

	public static OrderServiceImpl getOrderStorageServiceInstance() {
		if (orderStorageServiceInstance == null) {
			orderStorageServiceInstance = new OrderServiceImpl();
		}
		return orderStorageServiceInstance;
	}

	public String entityDetails(Order t) {

		StringBuffer str = new StringBuffer(t.getId()
				+ Separator.SEPARATOR.getS());
		for (Book book : t.getBooks()) {
			str.append(book.getBookId());
			str.append(Separator.BOOK_SEPARATOR_IN_ORDER.getS());

		}
		str.append(Separator.SEPARATOR.getS());
		str.append(t.isExecuted() + Separator.SEPARATOR.getS());
		str.append(t.getTotalPrice());
		return str.toString();

	}

	@Override
	public void addEntity(Order e) {
		Session session = null;
		Transaction transaction = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();

			orderDao.create(session, e);
            transaction.commit();
		} catch (HibernateException e1) {
			logger.error(e1.getMessage(), e1);
			transaction.rollback();
		}

	}

	public void updateEntity(Order e) {
		Session session = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			orderDao.update(session, e);
		} catch (HibernateException e1) {
			logger.error(e1.getMessage(), e1);
		}
	}

	public void removeEntityById(Integer id) {
		Transaction transaction = null;
		Session session = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			transaction = session.beginTransaction();
			Order order = orderDao.read(session, id);
			orderDao.delete(session, order);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
			transaction.rollback();
		}

	}

	@Override
	public boolean executeOrderById(Integer id) {
		Session session = null;
		try {
			session = HibernateSessionUtil.getSessionFactory().getCurrentSession();
			return orderDao.executeOrder(session, id);
		} catch (HibernateException e) {
			logger.error(e.getMessage(), e);
		}
		return false;
	}

}
